"""Browser Controller - Playwright-based automated browser."""

from pathlib import Path

from loguru import logger
from playwright.async_api import Browser, BrowserContext, Page, async_playwright


class BrowserController:
    """Manages Playwright browser instances for automation."""

    def __init__(
            self,
            headless: bool = True,
            user_data_dir: Path | None = None,
            extension_path: Path | None = None,
    ):
        """Initializes the BrowserController.

        Args:
            headless (bool): Whether to run the browser in headless mode. Defaults to True.
            user_data_dir (Path | None): Directory for persistent user data. Defaults to a subdirectory in the user's home.
            extension_path (Path | None): Path to browser extensions (e.g., cat-catch). Defaults to None.
        """
        self.headless = headless
        self.user_data_dir = user_data_dir or Path.home() / ".swiftshadow" / "browser_data"
        self.extension_path = extension_path

        self._playwright = None
        self._browser: Browser | None = None
        self._context: BrowserContext | None = None
        self._pages: dict[str, Page] = {}

        logger.info(
            f"浏览器控制器已初始化 - " f"无头模式: {headless}, 数据目录: {self.user_data_dir}"
        )

    async def start(self) -> None:
        """Starts the Playwright browser instance."""
        if self._browser is not None:
            logger.warning("浏览器已在运行")
            return

        logger.info("正在启动浏览器...")
        self._playwright = await async_playwright().start()

        # 确保用户数据目录存在
        self.user_data_dir.mkdir(parents=True, exist_ok=True)

        # 构建启动参数
        launch_args = [
            "--disable-blink-features=AutomationControlled",  # 隐藏自动化特征
        ]

        # 如果有扩展路径，加载扩展
        if self.extension_path and self.extension_path.exists():
            launch_args.extend(
                [
                    f"--disable-extensions-except={self.extension_path}",
                    f"--load-extension={self.extension_path}",
                ]
            )
            logger.info(f"已加载扩展: {self.extension_path}")

        # 启动持久化上下文（保留Cookie等）
        self._context = await self._playwright.chromium.launch_persistent_context(
            str(self.user_data_dir),
            headless=self.headless,
            args=launch_args,
            viewport={"width": 1920, "height": 1080},
            user_agent=(
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                "AppleWebKit/537.36 (KHTML, like Gecko) "
                "Chrome/120.0.0.0 Safari/537.36"
            ),
        )

        logger.success("浏览器已启动")

    async def stop(self) -> None:
        """Stops the Playwright browser instance and closes all associated pages."""
        if self._context is None:
            return

        logger.info("正在关闭浏览器...")

        # 关闭所有页面
        for page_id in list(self._pages.keys()):
            await self.close_page(page_id)

        # 关闭上下文
        await self._context.close()
        self._context = None

        # 停止Playwright
        if self._playwright:
            await self._playwright.stop()
            self._playwright = None

        logger.success("浏览器已关闭")

    async def new_page(self, url: str | None = None, page_id: str | None = None) -> Page:
        """Creates a new browser page.

        Args:
            url: 初始URL（可选）
            page_id: 页面ID（用于管理）

        Returns:
            Page: The newly created Playwright page object.
        """
        if self._context is None:
            await self.start()

        page = await self._context.new_page()

        # 注入反检测脚本
        await page.add_init_script(
            """
            Object.defineProperty(navigator, 'webdriver', {
                get: () => undefined
            });
        """
        )

        # 生成页面ID
        if page_id is None:
            page_id = f"page_{len(self._pages)}"

        self._pages[page_id] = page
        logger.debug(f"创建新页面: {page_id}")

        # 导航到URL
        if url:
            await page.goto(url, wait_until="domcontentloaded")
            logger.debug(f"页面已导航至: {url}")

        return page

    async def get_page(self, page_id: str) -> Page | None:
        """获取指定页面

        Args:
            page_id: 页面ID

        Returns:
            Page对象或None
        """
        return self._pages.get(page_id)

    async def close_page(self, page: Page) -> None:
        """Closes a given browser page.

        Args:
            page (Page): The Playwright page object to close.
        """
        page = self._pages.pop(page_id, None)
        if page:
            await page.close()
            logger.debug(f"页面已关闭: {page_id}")
            return True
        return False

    async def execute_script(self, page: Page, script: str) -> Any:
        """Executes JavaScript in the given page.

        Args:
            page (Page): The Playwright page object.
            script (str): The JavaScript code to execute.

        Returns:
            Any: The result of the JavaScript execution.
        """
        page = await self.get_page(page_id)
        if page is None:
            raise ValueError(f"页面不存在: {page_id}")

        return await page.evaluate(script)

    async def wait_for_selector(self, page: Page, selector: str, timeout: int = 30000) -> ElementHandle | None:
        """Waits for a selector to appear in the page.

        Args:
            page (Page): The Playwright page object.
            selector (str): The CSS selector to wait for.
            timeout (int): The maximum time in milliseconds to wait for the selector. Defaults to 30000.

        Returns:
            ElementHandle | None: The element handle if found, otherwise None.
        """
        page = await self.get_page(page_id)
        if page is None:
            raise ValueError(f"页面不存在: {page_id}")

        try:
            await page.wait_for_selector(selector, timeout=timeout)
            return True
        except Exception as e:
            logger.warning(f"等待元素超时: {selector} - {e}")
            return False

    async def screenshot(self, page: Page, path: Path) -> None:
        """Takes a screenshot of the current page.

        Args:
            page (Page): The Playwright page object.
            path (Path): The path to save the screenshot.
        """
        page = await self.get_page(page_id)
        if page is None:
            raise ValueError(f"页面不存在: {page_id}")

        try:
            await page.screenshot(path=str(path))
            logger.info(f"截图已保存: {path}")
            return True
        except Exception as e:
            logger.error(f"截图失败: {e}")
            return False

    async def get_cookies(self, page: Page) -> list[dict]:
        """Retrieves all cookies from the current page.

        Args:
            page (Page): The Playwright page object.

        Returns:
            list[dict]: A list of cookie dictionaries.
        """
        page = await self.get_page(page_id)
        if page is None:
            raise ValueError(f"页面不存在: {page_id}")

        return await page.context.cookies()

    async def set_cookies(self, page: Page, cookies: list[dict]) -> None:
        """Sets cookies for the current page.

        Args:
            page (Page): The Playwright page object.
            cookies (list[dict]): A list of cookie dictionaries to set.
        """
        if self._context is None:
            await self.start()

        await self._context.add_cookies(cookies)
        logger.debug(f"已设置 {len(cookies)} 个Cookie")

    async def clear_cookies(self, page: Page) -> None:
        """Clears all cookies for the current page.

        Args:
            page (Page): The Playwright page object.
        """

    async def intercept_requests(self, page_id: str, url_pattern: str, callback: callable) -> None:
        """Intercepts network requests for the specified page.

        Args:
            page_id (str): The ID of the page to monitor for requests.
            url_pattern (str): The URL pattern to match intercepted requests.
            callback (callable): The function to execute when a matching request is intercepted.
        """
        page = await self.get_page(page_id)
        if page is None:
            raise ValueError(f"页面不存在: {page_id}")

        await page.route(url_pattern, callback)
        logger.debug(f"已设置请求拦截: {url_pattern}")

    async def remove_intercept(self, page_id: str) -> None:
        """Removes network request interception for the specified page.

        Args:
            page_id (str): The ID of the page from which to remove interception.
        """
        page = await self.get_page(page_id)
        if page is None:
            logger.warning(f"页面不存在，无法移除拦截: {page_id}")
            return
        # Note: Playwright's page.unroute() requires the exact handler function
        # that was used with page.route(). This implementation assumes a simple
        # removal or a placeholder if handlers are not stored.
        logger.debug(f"尝试移除页面 {page_id} 的请求拦截 (功能待实现)")

    async def __aenter__(self) -> "BrowserController":
        """Enters the asynchronous context manager, starting the browser.

        Returns:
            BrowserController: The instance of the browser controller.
        """
        await self.start()
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb) -> None:
        """Exits the asynchronous context manager, stopping the browser."""
        await self.stop()
